package icu.d4peng.basic.database.druid.properties;

import com.alibaba.druid.filter.config.ConfigFilter;
import com.alibaba.druid.filter.encoding.EncodingConvertFilter;
import com.alibaba.druid.filter.logging.CommonsLogFilter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.filter.logging.Log4jFilter;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import icu.d4peng.basic.core.constant.ProjectConstant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;

import java.util.ArrayList;

/**
 * DruidProperties:Druid属性
 *
 * @author d4peng <a href="d4peng@qq.com">d4peng@qq.com</a>
 * @since 2023.12.02
 */
@EqualsAndHashCode(callSuper = true)
@Data
@ConfigurationProperties(prefix = DruidProperties.PREFIX)
public class DruidProperties extends DruidDataSource implements InitializingBean {

	public static final String PREFIX = ProjectConstant.PREFIX + ".database.druid";

	private final DataSourceProperties dataSourceProperties;

	/**
	 * aop配置
	 */
	private String[] aopPatterns;

	/**
	 * 统计界面Servlet
	 */
	private StatViewServlet statViewServlet = new StatViewServlet();

	/**
	 * 统计的拦截器
	 */
	private WebStatFilter webStatFilter = new WebStatFilter();

	/**
	 * 过滤器配置
	 */
	private Filter filter = new Filter();

	@Autowired
	public DruidProperties(DataSourceProperties dataSourceProperties) {
		dataSourceProperties.setType(getClass());
		this.dataSourceProperties = dataSourceProperties;
	}

	@Override
	public void afterPropertiesSet() {
		if (super.getUsername() == null) {
			super.setUsername(this.dataSourceProperties.determineUsername());
		}
		if (super.getPassword() == null) {
			super.setPassword(this.dataSourceProperties.determinePassword());
		}
		if (super.getUrl() == null) {
			super.setUrl(this.dataSourceProperties.determineUrl());
		}
		if (super.getDriverClassName() == null) {
			super.setDriverClassName(this.dataSourceProperties.getDriverClassName());
		}

		// 过滤器配置
		ArrayList<com.alibaba.druid.filter.Filter> filters = new ArrayList<>();
		if (this.getFilter().isConfig()) {
			filters.add(new ConfigFilter());
		}
		if (this.getFilter().isEncoding()) {
			filters.add(new EncodingConvertFilter());
		}
		if (this.getFilter().isSlf4j()) {
			filters.add(new Slf4jLogFilter());
		}
		if (this.getFilter().isLog4j()) {
			filters.add(new Log4jFilter());
		}
		if (this.getFilter().isLog4j2()) {
			filters.add(new Log4j2Filter());
		}
		if (this.getFilter().isCommonsLog()) {
			filters.add(new CommonsLogFilter());
		}
		if (this.getFilter().isWall()) {
			WallFilter wallFilter = new WallFilter();
			wallFilter.setConfig(new WallConfig());
			filters.add(wallFilter);
		}
		if (this.getFilter().isStat()) {
			filters.add(new StatFilter());
		}
		super.filters = filters;
	}

	@Override
	public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
		try {
			super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
		}
		catch (IllegalArgumentException ignore) {
			super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
		}
	}

	@Data
	public static class StatViewServlet {

		/**
		 * Enable StatViewServlet, default false.
		 */
		private boolean enabled = false;

		private String urlPattern;

		private String allow;

		private String deny;

		private String loginUsername;

		private String loginPassword;

		private String resetEnable;

	}

	@Data
	public static class WebStatFilter {

		/**
		 * Enable WebStatFilter, default false.
		 */
		private boolean enabled = false;

		private String urlPattern;

		private String exclusions;

		private String sessionStatMaxCount;

		private String sessionStatEnable;

		private String principalSessionName;

		private String principalCookieName;

		private String profileEnable;

	}

	@Data
	public static class Filter {

		private boolean stat = false;

		private boolean config = false;

		private boolean encoding = false;

		private boolean slf4j = false;

		private boolean log4j = false;

		private boolean log4j2 = false;

		private boolean commonsLog = false;

		private boolean wall = false;

	}

}
